

#ifndef EVALUATIONRUNNER_H_
#define EVALUATIONRUNNER_H_

#include <queue>
#include <pthread.h>
#include <iostream>
#include "Producer.h"
#include "../Packets/PubPkt.h"
#include "../Packets/RulePkt.h"
#include "ParamHandler.h"
#include "../Interface/OutputListener.h"
#include "../Common/Timer.h"
#include "../Packets/Pkt.h"
#include "../Interface/StorexEngine.h"

using namespace std;

/**
 * Memory shared between producer and consumer of packets
 */
typedef struct ContextStruct {
	pthread_cond_t *cond;					// Condition variable
	pthread_mutex_t *mutex;				// Mutex
	//Producer *p;									// Producer
	std::queue<PubPkt*> inputPubQueue;
	std::queue<SubPkt*> inputSubQueue;
	StorexEngine *engine;						// Engine
	ParamHandler *paramHandler;		// ParameterHandler
	std::queue<PktPtr> queue;		// Queue of packets
	bool finish;									// True if the producer finished its messages
	int dropped;									// Total number of packet dropped
} Context;

/**
 * This class creates a consumer and a producer to evaluate engine performance with
 * asynchronous message passing through a queue.
 */
class EvaluationRunner {
public:

	/**
	 * Constructor
	 */
	EvaluationRunner(ConfigHandler *configHandler, ParamHandler *parParamHandler, OutputListener *parOutputListener);

	/**
	 * Destructor
	 */
	virtual ~EvaluationRunner();

	/**
	 * Performs an evaluation test: returns the total number of packets dropped by the producer
	 */
	int startEval(std::queue<PktPtr> inputQueue);


private:
	Context context;			// Shared memory between producer and consumer
	StorexEngine *storexEngine;
	ParamHandler *paramHandler;

};

class PktHandleVisitor : public boost::static_visitor<> {
		StorexEngine *engine;
		ParamHandler *paramHandler;
	public:
		PktHandleVisitor(StorexEngine* parEngine, ParamHandler* parParamHandler): engine(parEngine), paramHandler(parParamHandler) { }
		void operator()(RulePkt * pkt) const;
		void operator()(PubPkt * pkt) const;
		void operator()(BackSubPkt * pkt) const;
		void operator()(UnSubPkt * pkt) const;
		void operator()(SubPkt * pkt) const;
		void operator()(PingPkt * pkt) const;
};


#endif
